Popular Searches
Popular Course Categories
Popular Courses

Sending information from one screen to another

Sending information from one screen to another

Flutter Navigation & Screens

Sending Information from One Screen to Another in Flutter

In Flutter, applications commonly contain multiple screens such as Home, Product Details, Profile, Settings, Cart, Checkout, Login, and Registration screens. When navigating from one screen to another, you often need to send information along with the navigation, such as a user ID, product object, name, email, selected item, or form data.

Flutter treats screens and pages as routes. The Navigator manages these routes, and Navigator.push() can be used to open a new route while passing data to the destination screen. :contentReference[oaicite:0]{index=0}


1. What Does Sending Information Between Screens Mean?

Sending information between screens means transferring a value or object from one Flutter screen to another while navigating.

For example:

  • Home Screen sends a product to Product Details Screen.
  • Login Screen sends a username to Dashboard Screen.
  • Product List Screen sends a product ID to Product Details Screen.
  • Profile Screen sends user information to Edit Profile Screen.
  • Form Screen sends entered information to a Confirmation Screen.

Basic Flow

Screen A
   |
   | Data + Navigation
   ↓
Screen B
   |
   | Uses received data
   ↓
Display Information

2. Why Do We Need to Pass Data Between Screens?

Real-world applications rarely keep every piece of information on a single screen. Different screens perform different responsibilities, so data must often travel between them.

  • To display details of a selected item.
  • To pass a logged-in user's information.
  • To pass IDs for database/API operations.
  • To pass form values.
  • To edit existing records.
  • To pass configuration or screen parameters.
  • To return a selected value to the previous screen.

3. Using Constructor Parameters

The simplest and most common approach is to pass data through the constructor of the destination widget.

Example: Sending a String

import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Home')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => const DetailsScreen(
                  message: 'Hello from Home Screen!',
                ),
              ),
            );
          },
          child: const Text('Open Details'),
        ),
      ),
    );
  }
}

class DetailsScreen extends StatelessWidget {
  final String message;

  const DetailsScreen({
    super.key,
    required this.message,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Details')),
      body: Center(
        child: Text(message),
      ),
    );
  }
}

void main() {
  runApp(
    const MaterialApp(
      home: HomeScreen(),
    ),
  );
}

How This Works

  1. The Home Screen has a button.
  2. The button calls Navigator.push().
  3. DetailsScreen is created.
  4. The message is passed through the constructor.
  5. The Details Screen displays the received message.

4. Passing Multiple Values

You can pass multiple values through a widget constructor.

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const ProfileScreen(
      name: 'Rahul',
      age: 25,
      email: '[email protected]',
    ),
  ),
);

The destination screen can receive these values:

class ProfileScreen extends StatelessWidget {
  final String name;
  final int age;
  final String email;

  const ProfileScreen({
    super.key,
    required this.name,
    required this.age,
    required this.email,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Profile')),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Name: $name'),
            Text('Age: $age'),
            Text('Email: $email'),
          ],
        ),
      ),
    );
  }
}

5. Passing an Object Between Screens

For real applications, passing a complete Dart object is often more useful than passing many individual values. Flutter's official navigation cookbook demonstrates passing a custom object to a new screen. :contentReference[oaicite:1]{index=1}

Step 1: Create a Model Class

class Product {
  final int id;
  final String name;
  final double price;

  const Product({
    required this.id,
    required this.name,
    required this.price,
  });
}

Step 2: Create a Product

final product = Product(
  id: 101,
  name: 'Laptop',
  price: 55000,
);

Step 3: Send the Object

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => ProductDetailsScreen(
      product: product,
    ),
  ),
);

Step 4: Receive the Object

class ProductDetailsScreen extends StatelessWidget {
  final Product product;

  const ProductDetailsScreen({
    super.key,
    required this.product,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(product.name),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              product.name,
              style: const TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.bold,
              ),
            ),
            Text('Product ID: ${product.id}'),
            Text('Price: ₹${product.price}'),
          ],
        ),
      ),
    );
  }
}

6. Complete Product List to Product Details Example

This is one of the most common real-world patterns. A list screen displays products, and when the user taps a product, the selected product is sent to a details screen.

import 'package:flutter/material.dart';

class Product {
  final int id;
  final String name;
  final double price;

  const Product({
    required this.id,
    required this.name,
    required this.price,
  });
}

class ProductListScreen extends StatelessWidget {
  ProductListScreen({super.key});

  final List products = const [
    Product(
      id: 1,
      name: 'Laptop',
      price: 55000,
    ),
    Product(
      id: 2,
      name: 'Smartphone',
      price: 30000,
    ),
    Product(
      id: 3,
      name: 'Headphones',
      price: 3000,
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Products'),
      ),
      body: ListView.builder(
        itemCount: products.length,
        itemBuilder: (context, index) {
          final product = products[index];

          return ListTile(
            title: Text(product.name),
            subtitle: Text('₹${product.price}'),
            trailing: const Icon(Icons.arrow_forward_ios),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) =>
                      ProductDetailsScreen(product: product),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

class ProductDetailsScreen extends StatelessWidget {
  final Product product;

  const ProductDetailsScreen({
    super.key,
    required this.product,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(product.name),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              product.name,
              style: const TextStyle(
                fontSize: 28,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 10),
            Text('Product ID: ${product.id}'),
            const SizedBox(height: 10),
            Text(
              '₹${product.price}',
              style: const TextStyle(
                fontSize: 22,
                fontWeight: FontWeight.bold,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

void main() {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      home: ProductListScreen(),
    ),
  );
}

Flow

Product List
     |
     | User taps Laptop
     ↓
Product object
     |
     | Navigator.push()
     ↓
Product Details
     |
     ↓
Display Laptop information

7. Sending Only an ID Between Screens

Sometimes you do not need to send an entire object. You can send an identifier such as a product ID or user ID.

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => ProductDetailsScreen(
      productId: 101,
    ),
  ),
);

Receive it on the destination screen:

class ProductDetailsScreen extends StatelessWidget {
  final int productId;

  const ProductDetailsScreen({
    super.key,
    required this.productId,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Product Details'),
      ),
      body: Center(
        child: Text(
          'Product ID: $productId',
        ),
      ),
    );
  }
}

This approach is useful when the destination screen will use the ID to fetch complete information from an API, database, or repository.


8. Passing Data Using RouteSettings

Flutter also supports passing information through RouteSettings.arguments. The destination screen can read the arguments using ModalRoute.of(context). :contentReference[oaicite:2]{index=2}

Sending Data

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const DetailsScreen(),
    settings: const RouteSettings(
      arguments: 'Hello Flutter',
    ),
  ),
);

Receiving Data

class DetailsScreen extends StatelessWidget {
  const DetailsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final message =
        ModalRoute.of(context)!.settings.arguments as String;

    return Scaffold(
      appBar: AppBar(
        title: const Text('Details'),
      ),
      body: Center(
        child: Text(message),
      ),
    );
  }
}

9. Passing a Custom Object Using RouteSettings

class User {
  final String name;
  final String email;

  const User({
    required this.name,
    required this.email,
  });
}

Send the object:

final user = User(
  name: 'Amit',
  email: '[email protected]',
);

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const UserScreen(),
    settings: RouteSettings(
      arguments: user,
    ),
  ),
);

Receive the object:

class UserScreen extends StatelessWidget {
  const UserScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final user =
        ModalRoute.of(context)!.settings.arguments as User;

    return Scaffold(
      appBar: AppBar(
        title: const Text('User'),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text('Name: ${user.name}'),
          Text('Email: ${user.email}'),
        ],
      ),
    );
  }
}

10. Passing Data Using Named Routes

Flutter provides Navigator.pushNamed(), which can pass an object through the arguments parameter. Flutter's API documentation allows values such as strings, integers, maps, and custom objects to be passed this way. :contentReference[oaicite:3]{index=3}

However, Flutter's current documentation notes that named routes are no longer recommended for most new applications. They remain useful for learning, maintaining existing applications, and understanding older Flutter navigation patterns. :contentReference[oaicite:4]{index=4}

Example

Navigator.pushNamed(
  context,
  '/profile',
  arguments: {
    'name': 'Rahul',
    'age': 25,
  },
);

Reading the Data

class ProfileScreen extends StatelessWidget {
  const ProfileScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final args =
        ModalRoute.of(context)!.settings.arguments
            as Map;

    return Scaffold(
      appBar: AppBar(
        title: const Text('Profile'),
      ),
      body: Column(
        children: [
          Text('Name: ${args['name']}'),
          Text('Age: ${args['age']}'),
        ],
      ),
    );
  }
}

11. Passing Data with onGenerateRoute

onGenerateRoute can be used when route creation needs to inspect the route settings and construct the appropriate screen.

MaterialApp(
  onGenerateRoute: (settings) {
    if (settings.name == '/profile') {
      final user =
          settings.arguments as User;

      return MaterialPageRoute(
        builder: (context) => UserScreen(
          user: user,
        ),
      );
    }

    return null;
  },
);

Navigate to the route:

Navigator.pushNamed(
  context,
  '/profile',
  arguments: user,
);

12. Returning Information from the Second Screen

Data can also travel in the opposite direction. A second screen can return a result to the first screen using Navigator.pop(context, result). The first screen can wait for the result returned by Navigator.push(). Flutter's official cookbook demonstrates this pattern for returning a user's selection. :contentReference[oaicite:5]{index=5}

Second Screen

ElevatedButton(
  onPressed: () {
    Navigator.pop(context, 'Selected Item');
  },
  child: const Text('Select'),
)

First Screen

Future openSelectionScreen() async {
  final result = await Navigator.push(
    context,
    MaterialPageRoute(
      builder: (context) => const SelectionScreen(),
    ),
  );

  if (!mounted) return;

  if (result != null) {
    print('Received: $result');
  }
}

Data Flow

Screen A
   |
   | Send data
   ↓
Screen B
   |
   | Navigator.pop(context, result)
   ↓
Screen A
   |
   ↓
Receive result

13. Sending Form Data to Another Screen

A common application requirement is to collect information on one screen and display it on another screen.

Form Screen

class FormScreen extends StatefulWidget {
  const FormScreen({super.key});

  @override
  State createState() => _FormScreenState();
}

class _FormScreenState extends State {
  final nameController = TextEditingController();

  @override
  void dispose() {
    nameController.dispose();
    super.dispose();
  }

  void submitForm() {
    final name = nameController.text;

    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => ResultScreen(
          name: name,
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Form'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          children: [
            TextField(
              controller: nameController,
              decoration: const InputDecoration(
                labelText: 'Enter Name',
              ),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: submitForm,
              child: const Text('Submit'),
            ),
          ],
        ),
      ),
    );
  }
}

Result Screen

class ResultScreen extends StatelessWidget {
  final String name;

  const ResultScreen({
    super.key,
    required this.name,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Result'),
      ),
      body: Center(
        child: Text(
          'Welcome, $name!',
          style: const TextStyle(
            fontSize: 24,
          ),
        ),
      ),
    );
  }
}

14. Sending Data from Login Screen to Dashboard

A typical login flow can pass basic user information to the dashboard.

class DashboardScreen extends StatelessWidget {
  final String username;

  const DashboardScreen({
    super.key,
    required this.username,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Dashboard'),
      ),
      body: Center(
        child: Text(
          'Welcome $username',
        ),
      ),
    );
  }
}

Navigate after login:

Navigator.pushReplacement(
  context,
  MaterialPageRoute(
    builder: (context) => DashboardScreen(
      username: 'Manish',
    ),
  ),
);

pushReplacement() can be useful when the previous screen should be replaced rather than kept as the next screen in the navigation stack. Flutter documents it as one of the additional Navigator navigation methods. :contentReference[oaicite:6]{index=6}


15. Sending Data from ListView to Details Screen

This is one of the most important patterns for Flutter developers.

ListView.builder(
  itemCount: products.length,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(products[index].name),
      onTap: () {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => ProductDetailsScreen(
              product: products[index],
            ),
          ),
        );
      },
    );
  },
)

The selected item is available using products[index].


16. Sending Data Using a Map

A Map can be used when a small amount of loosely structured data needs to be passed.

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const DetailsScreen(),
    settings: RouteSettings(
      arguments: {
        'id': 101,
        'name': 'Laptop',
        'price': 55000,
      },
    ),
  ),
);

Receive the Map:

final data =
    ModalRoute.of(context)!.settings.arguments
        as Map;

final id = data['id'];
final name = data['name'];
final price = data['price'];

When to Use a Model Instead

For larger applications, a dedicated Dart model class is generally easier to maintain than repeatedly accessing Map keys such as data['name'] and data['price'].


17. Sending Data Through a Selection Screen

Suppose a user needs to select a country.

Open Selection Screen

final selectedCountry = await Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const CountryScreen(),
  ),
);

Return Selected Country

ListTile(
  title: const Text('India'),
  onTap: () {
    Navigator.pop(context, 'India');
  },
)

Use Result

if (!mounted) return;

if (selectedCountry != null) {
  setState(() {
    country = selectedCountry;
  });
}

18. Passing Data for Editing

Another common pattern is sending an existing object to an edit screen.

class User {
  final String name;
  final String email;

  User({
    required this.name,
    required this.email,
  });
}

Send the user:

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => EditUserScreen(
      user: user,
    ),
  ),
);

The edit screen can display the existing values inside TextEditingController objects and allow the user to modify them.


19. Passing Data Between Three Screens

Data can travel through multiple screens.

Home Screen
    |
    | Product
    ↓
Product Screen
    |
    | Product + Quantity
    ↓
Checkout Screen
    |
    | Order Data
    ↓
Confirmation Screen

Example

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => CheckoutScreen(
      product: product,
      quantity: 2,
    ),
  ),
);

20. Passing Data Through a Custom Model

For complex applications, a model class makes the data structure clearer.

class Order {
  final int orderId;
  final String customerName;
  final double amount;
  final String status;

  const Order({
    required this.orderId,
    required this.customerName,
    required this.amount,
    required this.status,
  });
}

Send it:

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => OrderDetailsScreen(
      order: order,
    ),
  ),
);

Receive it:

class OrderDetailsScreen extends StatelessWidget {
  final Order order;

  const OrderDetailsScreen({
    super.key,
    required this.order,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Order #${order.orderId}'),
      ),
      body: Column(
        children: [
          Text(order.customerName),
          Text('Amount: ₹${order.amount}'),
          Text('Status: ${order.status}'),
        ],
      ),
    );
  }
}

21. Constructor vs RouteSettings

Feature Constructor RouteSettings
Easy to understand Yes Moderate
Type safety Strong Requires casting
Good for custom objects Yes Yes
Direct dependency visible Yes No
Suitable for simple navigation Excellent Good

22. Navigator.push() and Data Flow

Navigator.push() adds a route to the Navigator's route stack. It returns a Future, which can later complete with the result supplied when that route is popped. :contentReference[oaicite:7]{index=7}

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => SecondScreen(
      data: 'Hello',
    ),
  ),
);

Conceptually:

Navigator Stack

Before:
[Home]

After push:
[Home, SecondScreen]

23. Navigator.pop() and Returning Data

Navigator.pop() removes the current route. It can also provide a result to the route that originally pushed it. :contentReference[oaicite:8]{index=8}

Navigator.pop(context, 'Success');

The previous screen can receive the value:

final result = await Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const SecondScreen(),
  ),
);

print(result);

24. Type-Safe Data Passing

When possible, use typed constructor parameters or typed navigation results.

final result = await Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const SelectionScreen(),
  ),
);

This makes it clear that the screen is expected to return a String.


25. Handling Null Values

A returned value can be null if the user leaves the screen without returning a result.

final result = await Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const SelectionScreen(),
  ),
);

if (result != null) {
  print('Selected: $result');
} else {
  print('Nothing selected');
}

26. Handling Widget Lifecycle After await

When using await, the widget may no longer be mounted when execution resumes. If you need to call setState() or use the widget's context after the await, check mounted first.

final result = await Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const SelectionScreen(),
  ),
);

if (!mounted) return;

setState(() {
  selectedValue = result;
});

27. Sending Data to an API-Driven Details Screen

A useful architecture is to send only the ID and let the destination screen retrieve the latest information.

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => ProductDetailsScreen(
      productId: product.id,
    ),
  ),
);

Then the details screen can use the ID with a repository or API service.

Future loadProduct() async {
  final product = await productRepository
      .getProductById(productId);

  if (!mounted) return;

  setState(() {
    currentProduct = product;
  });
}

This pattern is useful when the destination screen should load current information instead of receiving a potentially outdated object.


28. Sending Information in an E-Commerce Application

Consider an e-commerce application:

Home
  ↓
Product List
  ↓
Product Details
  ↓
Cart
  ↓
Checkout
  ↓
Order Confirmation

Possible data transfers include:

From To Data
Product List Product Details Product object
Product Details Cart Product + quantity
Cart Checkout Cart items + total
Checkout Confirmation Order object

29. Common Mistakes

Mistake 1: Forgetting the Required Parameter

class DetailsScreen extends StatelessWidget {
  final String name;

  const DetailsScreen({
    super.key,
    required this.name,
  });
}

When creating this widget, name must be supplied.

Mistake 2: Incorrect Type Casting

final data =
    ModalRoute.of(context)!.settings.arguments as User;

Make sure the actual argument is a User object before casting it.

Mistake 3: Forgetting to Await a Result

final result = await Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const SelectionScreen(),
  ),
);

Mistake 4: Using a Map Everywhere

Maps can be convenient for small examples, but dedicated model classes make complex applications easier to maintain and refactor.

Mistake 5: Passing Too Much Unnecessary Data

If the destination only needs an ID, sending a large object may be unnecessary. Choose the smallest meaningful data required by the destination screen.


30. Best Practices

  • Prefer constructor parameters for straightforward screen-to-screen data transfer.
  • Use strongly typed model classes for complex data.
  • Pass only the data the destination actually needs.
  • Use IDs when the destination should load fresh data.
  • Use Navigator.pop() with a result when information needs to return to the previous screen.
  • Check for null when a navigation result is optional.
  • After an asynchronous navigation result, check mounted before updating widget state.
  • Keep navigation logic easy to understand and test.
  • For larger applications, use an appropriate routing/state-management architecture rather than passing large amounts of data through many screens.
  • For new applications, be aware that Flutter's current documentation does not recommend named routes for most applications. :contentReference[oaicite:9]{index=9}

31. Real-World Example: Student Details

Student Model

class Student {
  final String name;
  final String course;
  final String email;

  const Student({
    required this.name,
    required this.course,
    required this.email,
  });
}

Student List

final students = [
  const Student(
    name: 'Amit',
    course: 'Flutter',
    email: '[email protected]',
  ),
  const Student(
    name: 'Neha',
    course: 'Dart',
    email: '[email protected]',
  ),
];

Navigate to Student Details

ListView.builder(
  itemCount: students.length,
  itemBuilder: (context, index) {
    final student = students[index];

    return ListTile(
      title: Text(student.name),
      subtitle: Text(student.course),
      onTap: () {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) =>
                StudentDetailsScreen(student: student),
          ),
        );
      },
    );
  },
)

Student Details Screen

class StudentDetailsScreen extends StatelessWidget {
  final Student student;

  const StudentDetailsScreen({
    super.key,
    required this.student,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(student.name),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Name: ${student.name}'),
            Text('Course: ${student.course}'),
            Text('Email: ${student.email}'),
          ],
        ),
      ),
    );
  }
}

32. Constructor-Based Data Passing vs Shared State

Not every piece of application data should be manually passed through every screen.

Requirement Possible Approach
Small screen-specific value Constructor parameter
Selected object Constructor/model
Return selection Navigator.pop result
Legacy named navigation Route arguments
Application-wide state State-management solution
Server-side data Repository/API layer

33. Important Flutter Navigation Methods

Method Purpose
Navigator.push() Open a new route.
Navigator.pop() Close the current route and optionally return a result.
Navigator.pushReplacement() Replace the current route.
Navigator.pushAndRemoveUntil() Push a route and remove routes according to a condition.
Navigator.popUntil() Pop routes until a condition is satisfied.
Navigator.pushNamed() Navigate using a named route.

Flutter's navigation documentation lists these and other Navigator methods for managing the route stack. :contentReference[oaicite:10]{index=10}


34. Quick Revision

  • Flutter screens are represented as routes.
  • Navigator.push() opens another screen.
  • Constructor parameters are a simple way to send information.
  • Custom Dart objects can be passed between screens.
  • An ID can be passed when the destination should load its own data.
  • RouteSettings.arguments can carry route arguments.
  • Navigator.pop(context, result) can return information.
  • await Navigator.push() can receive a typed result.
  • Always handle nullable results when appropriate.
  • Check mounted after asynchronous operations before updating state.
  • Named routes support arguments but are not recommended for most new Flutter applications according to current Flutter documentation.

35. Interview Questions

  1. How do you send data from one Flutter screen to another?
  2. What is the easiest way to pass data to a new screen?
  3. How can you pass a custom Dart object between screens?
  4. What is the purpose of Navigator.push()?
  5. What is the purpose of Navigator.pop()?
  6. How can a screen return data to the previous screen?
  7. What is RouteSettings.arguments?
  8. How can you receive arguments using ModalRoute.of(context)?
  9. How can you pass data using Navigator.pushNamed()?
  10. Why might a model class be preferable to a Map?
  11. When should you pass an ID instead of a complete object?
  12. Why should you check mounted after awaiting navigation?
  13. What is the difference between push() and pushReplacement()?
  14. What happens to the Navigator stack when push() is called?
  15. Why are named routes not recommended for most new Flutter applications?

36. Practical Exercise

Create a Flutter application with the following flow:

Home Screen
     ↓
Student List
     ↓
Student Details
     ↓
Edit Student
     ↓
Return Updated Student
     ↓
Student List

Requirements

  1. Create a Student model.
  2. Create a list containing at least five students.
  3. Display students using ListView.builder.
  4. Pass the selected student to a details screen.
  5. Display the student's name, email, and course.
  6. Add an Edit button.
  7. Pass the student to the edit screen.
  8. Allow the user to modify the student's name.
  9. Return the updated name using Navigator.pop().
  10. Update the original screen after receiving the result.

37. Key Takeaways

Sending information from one screen to another is a fundamental Flutter development skill. For simple navigation, constructor parameters provide a clear and strongly typed approach. For more complex flows, custom model objects, IDs, route arguments, and returned navigation results can be used according to the application's requirements.

The most important pattern to remember is:

// Send
Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => DetailsScreen(
      data: value,
    ),
  ),
);

// Receive
class DetailsScreen extends StatelessWidget {
  final String data;

  const DetailsScreen({
    super.key,
    required this.data,
  });

  @override
  Widget build(BuildContext context) {
    return Text(data);
  }
}

38. Official Flutter Resources


39. Flutter Training Resources

For structured Flutter learning and course information, visit:

whatsapp